package com.usian.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.usian.article.client.ArticleFeign;
import com.usian.common.enums.AppHttpCodeEnum;
import com.usian.common.exception.LeadException;
import com.usian.common.threadlocal.UserThreadLocalUtils;
import com.usian.common.util.JsonUtils;
import com.usian.common.util.JwtUtils;
import com.usian.model.article.dtos.AuthorDto;
import com.usian.model.behavior.dtos.FollowBehaviorDto;
import com.usian.model.user.dtos.AppLoginDto;
import com.usian.model.user.dtos.UserRelationDto;
import com.usian.user.entity.ApUser;
import com.usian.user.entity.ApUserFan;
import com.usian.user.entity.ApUserFollow;
import com.usian.user.mapper.ApUserMapper;
import com.usian.user.service.IApUserFanService;
import com.usian.user.service.IApUserFollowService;
import com.usian.user.service.IApUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.usian.common.constants.message.FollowBehaviorConstants.FOLLOW_BEHAVIOR_TOPIC;

/**
 * <p>
 * APP用户信息表 服务实现类
 * </p>
 *
 * @author usian
 * @since 2022-09-29
 */
@Service
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements IApUserService {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Override
    public Map<String, Object> login(AppLoginDto dto) {
        //1、参数校验dto
        if(dto==null){
            throw new LeadException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //2、校验dto中的设备号、手机号和密码不能同时为空
        if (StringUtils.isBlank(dto.getEquipmentId()) && StringUtils.isBlank(dto.getPhone()) && StringUtils.isBlank(dto.getPassword())) {
            throw new LeadException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        Integer userId=0;
        //判断是否传递了手机号和密码
        if(StringUtils.isNotBlank(dto.getPhone()) && StringUtils.isNotBlank(dto.getPassword())){
            //根据手机号查询用户
            QueryWrapper<ApUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(ApUser::getPhone,dto.getPhone());
            ApUser apUser = this.getOne(queryWrapper);
            if(apUser==null){
                throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST,"用户不存在");
            }

            //校验密码是否正确
            boolean b = passwordEncoder.matches(dto.getPassword(), apUser.getPassword());
            if(!b){
                throw new LeadException(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
            }

            userId=apUser.getId();
        }else{
            //如果未传递，设备号登录（不登录、先看看）
            if(StringUtils.isBlank(dto.getEquipmentId())){
                throw new LeadException(AppHttpCodeEnum.PARAM_REQUIRE);
            }
        }
        //生成token，返回前端
        String token = JwtUtils.generateTokenExpireInMinutes(userId, 60);
        Map<String, Object> map = new HashMap<>();
        map.put("token",token);
        return map;
    }

    @Autowired
    private ArticleFeign articleFeign;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Override
    public void follow(UserRelationDto dto) {
        //1、参数校验
        if(dto==null || dto.getOperation()<0 || dto.getOperation()>1){
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2、从线程中获取用户id，如果未获取到，说明是未登录状态
        Integer userId = UserThreadLocalUtils.getUserId();
        if(userId==null){
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN);
        }
        //3、根据页面提交的作者id，通过feign远程调用查询作者信息
        Integer authorId = dto.getAuthorId();
        if(authorId==null){
            throw new LeadException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        AuthorDto authorDto = articleFeign.findById(authorId);
        if(authorDto==null){
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST,"作者信息不存在");
        }
        //获取作者对应的App社交账号id
        Integer followId = authorDto.getUserId();
        //4、判断是关注还是取消关注行为
        if(dto.getOperation()==1){
            //4.1、如果是关注行为，记录关注表和粉丝表数据
            followUser(userId,followId,dto.getArticleId());

        }else{
            //4.2、如果是取消关注行为，删除关注表和粉丝表数据
            cancelFollowUser(userId,followId);
        }
    }

    @Autowired
    private IApUserFollowService apUserFollowService;

    @Autowired
    private IApUserFanService apUserFanService;

    @Override
    public ApUserFollow findByUserIdAndFollowId(Integer userId, Integer followId) {
        QueryWrapper<ApUserFollow> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ApUserFollow::getFollowId,followId).eq(ApUserFollow::getUserId,userId);
        ApUserFollow userFollow = apUserFollowService.getOne(queryWrapper);
        return userFollow;
    }

    //取消关注操作
    private void cancelFollowUser(Integer userId, Integer followId) {
        //删除关注表数据
        QueryWrapper<ApUserFollow> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(ApUserFollow::getFollowId,followId).eq(ApUserFollow::getUserId,userId);
        boolean b = apUserFollowService.remove(queryWrapper);
        if(!b){
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"删除关注数据失败");
        }
        //删除粉丝数据
        QueryWrapper<ApUserFan> queryWrapper1 = new QueryWrapper<>();
        //userId（登录用户，是粉丝）   followId（关注的作者）
        queryWrapper1.lambda().eq(ApUserFan::getFansId,userId).eq(ApUserFan::getUserId,followId);
        boolean b1 = apUserFanService.remove(queryWrapper1);
        if(!b1){
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"删除粉丝数据失败");
        }
    }

    //记录关注操作
    private void followUser(Integer userId, Integer followId, Long articleId) {
        //查询关注的作者是否存在
        ApUser apUser = this.getById(followId);
        if(apUser==null){
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST,"作者信息不存在");
        }
        //查询当前用户是否关注了该作者
        QueryWrapper<ApUserFollow> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ApUserFollow::getFollowId,followId).eq(ApUserFollow::getUserId,userId);
        ApUserFollow userFollow = apUserFollowService.getOne(queryWrapper);
        if(userFollow!=null){
            throw new LeadException(AppHttpCodeEnum.DATA_EXIST,"已经关注过该作者");
        }
        //如果没有关注，则记录关注操作
        userFollow = new ApUserFollow();
        userFollow.setUserId(userId);
        userFollow.setFollowId(followId);
        userFollow.setFollowName(apUser.getName());
        userFollow.setCreatedTime(new Date());
        userFollow.setLevel(0);//关注度  0 偶尔感兴趣  1 一般  2 经常  3 高度
        userFollow.setIsNotice(true);
        boolean b = apUserFollowService.save(userFollow);
        if(!b){
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }

        //查询粉丝记录是否存在
        //查询粉丝信息
        ApUser fanUser = this.getById(userId);
        QueryWrapper<ApUserFan> queryWrapper1 = new QueryWrapper<>();
        //userId（登录用户，是粉丝）   followId（关注的作者）
        queryWrapper1.lambda().eq(ApUserFan::getFansId,userId).eq(ApUserFan::getUserId,followId);
        ApUserFan userFan = apUserFanService.getOne(queryWrapper1);
        //如果没有粉丝，则记录粉丝数据
        if (userFan!=null) {
            throw new LeadException(AppHttpCodeEnum.DATA_EXIST,"粉丝已经存在");
        }
        userFan= new ApUserFan();
        userFan.setUserId(followId);
        userFan.setFansId(userId);
        userFan.setFansName(fanUser.getName());
        userFan.setLevel(0);
        userFan.setCreatedTime(new Date());
        userFan.setIsDisplay(true);
        userFan.setIsShieldComment(false);
        userFan.setIsShieldLetter(false);
        boolean b1 = apUserFanService.save(userFan);
        if(!b1){
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"保存粉丝数据失败");
        }

        //生产一条关注行为的消息
        FollowBehaviorDto followBehaviorDto = new FollowBehaviorDto();
        followBehaviorDto.setUserId(userId);
        followBehaviorDto.setFollowId(followId);
        followBehaviorDto.setArticleId(articleId);
        kafkaTemplate.send(FOLLOW_BEHAVIOR_TOPIC, JsonUtils.toString(followBehaviorDto));
    }
}
